package org.example.chat.security.components.utils;

import cn.hutool.json.JSONUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.example.chat.security.config.SecurityConfigProperties;
import org.example.chat.security.entity.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.UUID;

/**
 * JWT工具类
 * @author cheval
 */
@Slf4j
@Component
public class JWTUtils {

    @Autowired
    private SecurityConfigProperties properties;
    private String bearer = "Bearer";
    private String payloadKey = "payload";

    public String generateToken(UserDetails payload) {
        JwtBuilder builder = Jwts.builder();
        String token = builder
                // header
                .setHeaderParam("type","jwt")
                .setHeaderParam("alg",properties.getJwtConfig().getSignatureAlgorithm().getValue())
                // payload
                .claim(payloadKey, JSONUtil.toJsonStr(payload))
                .setExpiration(generateExpirationDate())
                .setId(UUID.randomUUID().toString())
                // 签名
                .signWith(properties.getJwtConfig().getSignatureAlgorithm(),properties.getJwtConfig().getSecret())
                .compact();
        return token;
    }

    /**
     * 验证token是否有效,有效返回true, 无效返回false
     * @param token
     * @return
     */
    public boolean isValid(String token){
        if (token == null || token.equals("")) {
            return false;
        }

        if (token.startsWith(bearer)) {
            token = token.substring(bearer.length() + 1);
        }

        UserDetails userInfoFromToken = getUserInfoFromToken(token);
        if (userInfoFromToken == null) {
            return false;
        }
        if (isTokenExpired(token)) {
            return false;
        }
        return true;
    }


    /**
     * 判断token是否失效
     * @param token
     * @return
     */
    private boolean isTokenExpired(String token) {
        if (token == null) {
            return false;
        }
        if (token.startsWith(bearer)) {
            token = token.substring(bearer.length() + 1);
        }
        Date expireDate = getExpiredDateFromToken(token);
        return expireDate.before(new Date());
    }

    /**
     * 从token中获取过期时间
     * @param token
     * @return
     */
    private Date getExpiredDateFromToken(String token) {
        if (token == null) {
            return null;
        }
        if (token.startsWith(bearer)) {
            token = token.substring(bearer.length() + 1);
        }
        Claims claims = getClaimsFormToken(token);
        return claims.getExpiration();
    }

    /**
     * 从token中获取登录用户信息
     */
    public UserDetails getUserInfoFromToken(String token) {
        if (token != null) {
            if (token.startsWith(bearer)) {
                token = token.substring(bearer.length() + 1);
            }
            Claims claims = getClaimsFormToken(token);
            if (claims == null) {
                return null;
            }
            String jsonUserDetails = (String)claims.get(payloadKey);
            try {
                return JSONUtil.toBean(jsonUserDetails, LoginUser.class);
            } catch (Exception e) {
                log.error(e.getMessage());
                return null;
            }
        }
        return null;
    }

    /**
     * 从token中获取荷载
     * @param token
     * @return
     */
    private Claims getClaimsFormToken(String token) {
        if (token == null) {
            return null;
        }
        if (token.startsWith(bearer)) {
            token = token.substring(bearer.length());
        }
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(properties.getJwtConfig().getSecret())
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            return null;
        }
        return claims;
    }

    /**
     * 生成token失效时间
     * @return Date
     */
    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + properties.getJwtConfig().getExpirationTime() * 1000);
    }
}
